package de.schmidke.palmreader;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import com.google.gdata.client.Query;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactGroupEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.contacts.GroupMembershipInfo;
import com.google.gdata.data.extensions.Email;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.Im;
import com.google.gdata.data.extensions.PhoneNumber;
import com.google.gdata.data.extensions.PostalAddress;
import com.google.gdata.util.ServiceException;

public class GoogleConnect {
	private static final String EP_PALMID = "PALMID";
	private ContactsService myService;
	private Collection<ContactEntry> allEntries;
	private Map<String, ContactEntry> palmEntries;
	private Map<String, ContactGroupEntry> allGroups;
	private String user;
	private String pwd;
	private URL contactFeed;
	private URL groupFeed;

	public GoogleConnect(String user, String pwd) throws MalformedURLException {
		this.user = user;
		this.pwd = pwd;
		groupFeed = new URL("http://www.google.com/m8/feeds/groups/" + user
				+ "/full");
		contactFeed = new URL("http://www.google.com/m8/feeds/contacts/" + user
				+ "/full");
	}

	public void run(AddressDat ad) throws Exception {
		System.out.println("Verbinde mit ContactsService ...");
		myService = new ContactsService("de.schmidke-palmsync-1");
		System.out.println("Melde Benutzer " + user + " an ...");
		myService.setUserCredentials(user, pwd);
		pwd = null;
		System.out.println("Lade vorhandene Kontakte ...");
		loadAllContacts();
		System.out.println("" + allEntries.size() + " Kontakte gefunden.");
		System.out.println("Lade vorhandene Gruppen ...");
		loadAllGroups();
		System.out.println("" + allGroups.size() + " Gruppen gefunden.");
		System.out.println("Synchronisiere ...");
		for (CategoryEntry ce : ad.getCategories()) {
			addOrUpdate(ce);
		}
		for (AddressEntry ae : ad.getAddressEntries()) {
			addOrUpdate(ae);
		}
	}

	private void addOrUpdate(CategoryEntry ce) throws IOException,
			ServiceException {
		if (allGroups.containsKey(ce.getLongName()))
			return;
		ContactGroupEntry group = new ContactGroupEntry();
		group.setTitle(new PlainTextConstruct(ce.getLongName()));
		allGroups.put(ce.getLongName(), myService.insert(groupFeed, group));
	}

	private void checkContact(ContactEntry ce, PalmPhoneNumber pn) {
		if (pn == null)
			return;
		if (pn.getNumber() == null)
			return;
		if (pn.getNumber().length() == 0)
			return;
		if (pn.getLabelid() == 4) {
			checkEMail(ce, pn);
		} else {
			checkPhone(ce, pn);
		}
	}

	private void checkPhone(ContactEntry ce, PalmPhoneNumber ppn) {
		for (PhoneNumber pn : ce.getPhoneNumbers()) {
			if (ppn.getLabel().equals(pn.getLabel())
					&& pn.getPhoneNumber().equals(ppn.getNumber())) {
				pn.setPrimary(ppn.isDefault());
				return;
			}
		}
		PhoneNumber pn = new PhoneNumber();
		pn.setLabel(ppn.getLabel());
		pn.setPhoneNumber(ppn.getNumber());
		pn.setPrimary(ppn.isDefault());
		ce.addPhoneNumber(pn);
	}

	private void checkEMail(ContactEntry ce, PalmPhoneNumber ppn) {
		for (Email pn : ce.getEmailAddresses()) {
			if (pn.getAddress().equals(ppn.getNumber())) {
				return;
			}
		}
		Email pn = new Email();
		pn.setAddress(ppn.getNumber());
		pn.setLabel("Privat");
		ce.addEmailAddress(pn);
	}

	private void ap(StringBuilder an, String was) {
		ap(an, was, "\n");
	}

	private void ap(StringBuilder an, String was, String dlim) {
		if (was == null)
			return;
		if (was.length() == 0)
			return;
		if (was.startsWith("GARMIN "))
			return;
		if (an.length() > 0)
			an.append(dlim);
		an.append(was);
	}

	private void addOrUpdate(AddressEntry ae) throws Exception {
		String palmid = ae.getIdstring();
		ContactEntry contact = palmEntries.get(palmid);
		boolean create = false;
		if (contact == null) {
			create = true;
			contact = new ContactEntry();
			ExtendedProperty pid = new ExtendedProperty();
			pid.setName(EP_PALMID);
			pid.setValue(palmid);
			contact.addExtendedProperty(pid);
		}
		contact.setTitle(new PlainTextConstruct(ae.getFullName()));
		System.out.print("\r" + ae.getFullName() + "             ");
		for (PalmPhoneNumber ppn : ae.getPhone()) {
			checkContact(contact, ppn);
		}
		StringBuilder notiz = new StringBuilder();
		Waypoint wp = ae.getWaypoint();
		if (wp != null) {
			notiz.append(wp.getGeotag());
		}
		ap(notiz, ae.getNote());
		ap(notiz, ae.getCustom1());
		ap(notiz, ae.getCustom2());
		ap(notiz, ae.getCustom3());
		ap(notiz, ae.getCustom4());
		contact.setContent(new PlainTextConstruct(notiz.toString()));
		// private int category;

		contact.getPostalAddresses().clear();
		for (AddressEntry.Address address : ae.getAddresses()) {
			notiz.setLength(0);
			ap(notiz, address.getAddress());
			ap(notiz, (address.getZip() + " " + address.getCity()).trim());
			ap(notiz, address.getState());
			ap(notiz, address.getCountry());
			if (notiz.length() > 0) {
				PostalAddress pa = new PostalAddress();
				pa.setValue(notiz.toString());
				if (ae.getCompany().length() > 0) {
					pa.setLabel("Business");
				} else {
					pa.setLabel("Private");
				}
	
				contact.addPostalAddress(pa);
			}
		}

		CategoryEntry ce = ae.getCategory();
		ContactGroupEntry cge = null;
		if (ce == null) {
			cge = allGroups.get("System Group: My Contacts");
		} else {
			cge = allGroups.get(ce.getLongName());
		}
		String href = cge.getId();
		boolean vorh = false;
		for (GroupMembershipInfo gmi : contact.getGroupMembershipInfos()) {
			String gmihref = gmi.getHref();
			if (gmihref.equals(href)) {
				vorh = true;
				break;
			}
		}
		if (!vorh) {
			GroupMembershipInfo gmi = new GroupMembershipInfo();
			gmi.setHref(href);
			contact.addGroupMembershipInfo(gmi);
		}
		if (create) {
			myService.insert(contactFeed, contact);
		} else {
			myService.update(new URL(contact.getEditLink().getHref()), contact);
		}

	}

	public void printAllContacts(ContactsService myService)
			throws ServiceException, IOException {
		// Request the feed
		Query q = new Query(contactFeed);
		q.setMaxResults(Integer.MAX_VALUE);
		ContactFeed resultFeed = myService.query(q, ContactFeed.class);
		// Print the results
		System.out.println(resultFeed.getTitle().getPlainText());
		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			ContactEntry entry = resultFeed.getEntries().get(i);
			System.out.println("\t" + entry.getTitle().getPlainText());

			System.out.println("Email addresses:");
			for (Email email : entry.getEmailAddresses()) {
				System.out.print(" " + email.getAddress());
				if (email.getRel() != null) {
					System.out.print(" rel:" + email.getRel());
				}
				if (email.getLabel() != null) {
					System.out.print(" label:" + email.getLabel());
				}
				if (email.getPrimary()) {
					System.out.print(" (primary) ");
				}
				System.out.print("\n");
			}

			System.out.println("IM addresses:");
			for (Im im : entry.getImAddresses()) {
				System.out.print(" " + im.getAddress());
				if (im.getLabel() != null) {
					System.out.print(" label:" + im.getLabel());
				}
				if (im.getRel() != null) {
					System.out.print(" rel:" + im.getRel());
				}
				if (im.getProtocol() != null) {
					System.out.print(" protocol:" + im.getProtocol());
				}
				if (im.getPrimary()) {
					System.out.print(" (primary) ");
				}
				System.out.print("\n");
			}

			System.out.println("Groups:");
			for (GroupMembershipInfo group : entry.getGroupMembershipInfos()) {
				String groupHref = group.getHref();
				System.out.println("  Id: " + groupHref);
			}

			System.out.println("Extended Properties:");
			for (ExtendedProperty property : entry.getExtendedProperties()) {
				if (property.getValue() != null) {
					System.out.println("  " + property.getName() + "(value) = "
							+ property.getValue());
				} else if (property.getXmlBlob() != null) {
					System.out.println("  " + property.getName()
							+ "(xmlBlob)= " + property.getXmlBlob().getBlob());
				}
			}

			String photoLink = entry.getContactPhotoLink().getHref();
			System.out.println("Photo Link: " + photoLink);

			System.out.println("Contact's ETag: " + entry.getEtag());
		}
	}

	public void loadAllContacts() throws ServiceException, IOException {
		// Request the feed
		Query q = new Query(contactFeed);
		q.setMaxResults(Integer.MAX_VALUE);
		ContactFeed resultFeed = myService.query(q, ContactFeed.class);
		allEntries = new ArrayList<ContactEntry>(resultFeed.getEntries());
		palmEntries = new HashMap<String, ContactEntry>();
		for (ContactEntry ce : allEntries) {
			for (ExtendedProperty ep : ce.getExtendedProperties()) {
				if (ep.getName().equals(EP_PALMID)) {
					palmEntries.put(ep.getValue(), ce);
				}
			}

		}
	}

	public void loadAllGroups() throws ServiceException, IOException {
		// Request the feed
		ContactGroupFeed resultFeed = myService.getFeed(groupFeed,
				ContactGroupFeed.class);
		allGroups = new HashMap<String, ContactGroupEntry>();
		for (ContactGroupEntry cge : resultFeed.getEntries()) {
			allGroups.put(cge.getTitle().getPlainText(), cge);
		}
	}

	public void printAllGroups() throws ServiceException, IOException {
		// Request the feed
		ContactGroupFeed resultFeed = myService.getFeed(groupFeed,
				ContactGroupFeed.class);
		// Print the results
		System.out.println(resultFeed.getTitle().getPlainText());

		for (int i = 0; i < resultFeed.getEntries().size(); i++) {
			ContactGroupEntry groupEntry = resultFeed.getEntries().get(i);
			System.out.println("Id: " + groupEntry.getId());
			System.out.println("Group Name: "
					+ groupEntry.getTitle().getPlainText());
			System.out.println("Last Updated: " + groupEntry.getUpdated());
			System.out.println("Extended Properties:");
			for (ExtendedProperty property : groupEntry.getExtendedProperties()) {
				if (property.getValue() != null) {
					System.out.println("  " + property.getName() + "(value) = "
							+ property.getValue());
				} else if (property.getXmlBlob() != null) {
					System.out.println("  " + property.getName()
							+ "(xmlBlob) = " + property.getXmlBlob().getBlob());
				}
			}
			System.out.println("Self Link: "
					+ groupEntry.getSelfLink().getHref());
			if (!groupEntry.hasSystemGroup()) {
				// System groups do not have an edit link
				System.out.println("Edit Link: "
						+ groupEntry.getEditLink().getHref());
				System.out.println("ETag: " + groupEntry.getEtag());
			}
			if (groupEntry.hasSystemGroup()) {
				System.out.println("System Group Id: "
						+ groupEntry.getSystemGroup().getId());
			}
		}
	}
}
